<?php
  class Core_SSH_PacketDisolver{
    private $file_descriptor;
    
    private $content;
    
    private $packet_type;
    
    private $key = null;
    
    private $tdes;
    
    private $raw_inbuff = null;

    public function __construct($file_descriptor){
      $this->file_descriptor = $file_descriptor;
    }
  
    public function setKey($key, &$tdes){
      $this->key = $key;
      
      $this->tdes = $tdes;
    }

	  public function getData(){
	    return $this->content;
	  }
    
	  public function getPacketType(){
	    return ord($this->packet_type);
	  }
	  
	  public function readPacket(){
	  	/**
      * handle raw read buffer
      * make sure we know expected length of packet
      */
	  	if($this->raw_inbuff == null || strlen($this->raw_inbuff) < 4){
      	/**
        * it's empty
        */
        $this->raw_inbuff = fread($this->file_descriptor, 4 - strlen($this->raw_inbuff));
        
        if(strlen($this->raw_inbuff) < 4){
          $this->content = "";
          
          return;
        }
      }
      
      /**
      * read into raw buffer whole packet
      */
      $subs_raw_inbuff = substr($this->raw_inbuff, 0, 4);
      
      $len_raw_inbuff = strlen($this->raw_inbuff) - 4;
      
      $dwordToInt_first = Core_SSH_Functions::dwordToInt($subs_raw_inbuff);
      
      if($dwordToInt_first > $len_raw_inbuff - (8 - ((Core_SSH_Functions::dwordToInt(substr($this->raw_inbuff, 0, 4))) % 8))){
        $bytes_missing = Core_SSH_Functions::dwordToInt(substr($this->raw_inbuff,0,4)) -(strlen($this->raw_inbuff) - 4 -(8-((Core_SSH_Functions::dwordToInt(substr($this->raw_inbuff,0,4))) % 8)));
        
        $this->raw_inbuff .= fread($this->file_descriptor, $bytes_missing);
        
        if(Core_SSH_Functions::dwordToInt(substr($this->raw_inbuff,0,4)) > strlen($this->raw_inbuff) - 4){
          die("FUCK");
          /**
          * packet is still not completed, try it next time
          */
          $this->content = "";
          
          return ;
        } 
        elseif(Core_SSH_Functions::dwordToInt(substr($this->raw_inbuff,0,4)) < strlen($this->raw_inbuff) - 4 -(8-((Core_SSH_Functions::dwordToInt(substr($this->raw_inbuff,0,4))) % 8))){
        	die("FUCK@");
          throw new Core_SSH_Exception('OPS!! ALGO MUITO ESTRANHO ACONTECEU!!!');
        }
      }
      
      /**
      * at this point $this->raw_inbuff should contain whole packet
      */
      
      /**
      * how long packet is
      */
      $pos = 0;
      
      $data = substr($this->raw_inbuff,$pos,4); $pos += 4;
      
      $packet_len = Core_SSH_Functions::dwordToInt($data);
      
      $padding_len = 8-(($packet_len) % 8);
      
      if($this->key == null){
        /**
        * read padding
        */
        $padding = substr($this->raw_inbuff, $pos, $padding_len); 
        
        $pos += $padding_len;
        
        /**
        * now packet type
        */
        $packet_type = substr($this->raw_inbuff, $pos, 1); 
        
        $pos += 1;
        
        /**
        * data
        */
        $content = substr($this->raw_inbuff, $pos, $packet_len - 5); 
        
        $pos += $packet_len - 5;
          
        $crc = substr($this->raw_inbuff, $pos, 4);
        
        $pos += 4;
      } 
      else{
        /**
        * encrypted data CRYPT
        */
        $enc_content = substr($this->raw_inbuff, $pos, $packet_len + $padding_len);
        
        $pos += $packet_len + $padding_len;
        
        /**
        * decrypt packet
        */
        $this->tdes->decrypt($enc_content);
        
        $dec_content = $enc_content;
        
        $xpos = 0;
        
        $padding = substr($dec_content, $xpos, $padding_len); 
        
        $xpos += $padding_len;
        
        $packet_type = substr($dec_content, $xpos, 1); 
        
        $xpos += 1;
        
        $content = substr($dec_content, $xpos, $packet_len - 5); 
        
        $xpos += $packet_len - 5;
        
        $crc = substr($dec_content, $xpos, 4);
      }

      /**
      * CRC - TODO: checks
      */
      if($crc != Core_SSH_Functions::crc($padding. $packet_type. $content)){
      	throw new Exception("!!!ATENÇÃO!!! CRC Perigoso no pacote vindo do servidor");
      }
      
      $this->packet_type = $packet_type;
      
      if($packet_type == SSH_SMSG_EXITSTATUS){
        throw new Exception('CONEXÃO ENCERRADA.');
      }
      
      $this->content = $content;
      
      /**
      * null raw read buffer
      */
      $this->raw_inbuff = null;
    }
  }